use model_graph_types::{
    database::{DataSource, DatabaseType},
    datasource::{DataSourceConnector, QueryCondition},
    modeling::{
        meta::{get_meta_classes, SYSTEM_DOMAIN_IDENTIFIER},
        system_meta_database, Class, ClassAttribute, ClassGetter, MetaConnector,
    },
};

use crate::{connector::SimpleDataSourceConnector, modeling_connector::SimpleMetaConnector};

pub mod mysql;
pub mod sqlite;

pub async fn generate_sql(
    domain_identifier: &String,
    database_type: DatabaseType,
) -> anyhow::Result<Vec<String>> {
    tracing::debug!("generate sql: {} {:?}", domain_identifier, database_type);
    let meta_datasource = system_meta_database()?;

    let meta_datasource_option = Some(meta_datasource.clone());

    let classes = if domain_identifier == SYSTEM_DOMAIN_IDENTIFIER {
        get_meta_classes()?
    } else {
        let ds_connector = SimpleDataSourceConnector::default();
        //获取所有的持久化的类型
        let mut query_conditions = QueryCondition::with_attribute(
            String::from("domain_identifier"),
            domain_identifier.clone(),
        )?;
        query_conditions.set_attribute(String::from("persistent"), String::from("1"))?;

        let values = ds_connector
            .instance_query(
                &meta_datasource_option,
                &meta_datasource,
                &Class::get_identifier()?,
                query_conditions,
                None,
                None,
            )
            .await?
            .data;

        let mut classes = vec![];
        for class_value in values {
            let mut class: Class = class_value.try_into()?;
            //
            _fill_attributes(&meta_datasource, &mut class).await?;
            classes.push(class);
        }
        classes
    };
    //
    let mut sqls = vec![];
    tracing::debug!("{:?}", classes);

    let meta_connector = SimpleMetaConnector::default();
    for class in classes {
        let persistence = meta_connector
            .get_class_persistence(&class.identifier)
            .await?;
        //
        match &database_type {
            DatabaseType::SQLite => {
                sqls.push(sqlite::class_struct_sql(&meta_datasource, class, persistence).await?)
            }
            DatabaseType::MySQL => {
                sqls.push(mysql::class_struct_sql(&meta_datasource, class, persistence).await?)
            }
            DatabaseType::Dgraph => {}
            _ => {
                tracing::error!("不支持的数据库类型:{:?}", database_type);
                return Err(anyhow::anyhow!("不支持的数据库类型:{:?}", database_type));
            }
        }
    }

    Ok(sqls)
}

async fn _fill_attributes(meta_datasource: &DataSource, class: &mut Class) -> anyhow::Result<()> {
    let ds_connector = SimpleDataSourceConnector::default();
    let meta_datasource_option = Some(meta_datasource.clone());

    let query_conditions =
        QueryCondition::with_attribute(String::from("class_identifier"), class.identifier.clone())?;

    let attrs = ds_connector
        .instance_query(
            &meta_datasource_option,
            &meta_datasource,
            &ClassAttribute::get_identifier()?,
            query_conditions,
            None,
            None,
        )
        .await?
        .data;
    if attrs.len() > 0 {
        let mut attributes = vec![];
        for attr_value in attrs {
            attributes.push(attr_value.try_into()?);
        }
        class.attributes = Some(attributes);
    }

    Ok(())
}
